<template>
  <!-- 执行检验 -->
  <!-- IQC20240801000018 -->
  <div class="designer" v-loading="template.loading" element-loading-text="检验模板加载中,请稍后..." element-loading-spinner="el-icon-loading">
    <div class="container">
      <div class="editorArea">
        <div class="menuBtns" v-if="!operateBtn">
          尺寸:
          <el-select class="menuItem" style="width: 80px" v-model="jsPDFOptions.format" size="mini" placeholder="请选择尺寸">
            <el-option v-for="item in jsPDFOptions.pages" :key="item.value" :label="item.label" :value="item.value"> </el-option>
          </el-select>
          宽度:
          <el-input class="menuItem" style="width: 80px" size="mini" disabled v-model="printStyle.width" />
          高度:
          <el-input class="menuItem" style="width: 80px" size="mini" disabled v-model="printStyle.height" />
          <el-button size="mini" type="success" icon="el-icon-printer" @click="exportPdf">导出PDF</el-button>
          <el-button size="mini" type="success" icon="el-icon-printer" @click="exportExcel">导出EXCEL</el-button>
        </div>
        <div class="editor-canvas" v-if="dataJson.rows && dataJson.rows.length > 0">
          <div class="grid-canvas" :style="canvasStyle">
            <table v-if="operateBtn" ref="tableDom" id="pdf" class="template-table" border="1" cellspacing="0" cellpadding="0" :style="computedTableStyle">
              <colgroup>
                <col :style="{ width: (item.width || baseTableConfig.cellWidth) + 'px' }" v-for="(item, index) in xAxisNum" :key="index" />
              </colgroup>
              <tr v-for="(item, index) in dataJson.rows" :key="index">
                <td
                  v-for="(cItem, cIndex) in computedNotHide(item.cells)"
                  :key="cIndex"
                  :x="cItem.x"
                  :y="cItem.y"
                  :class="['tdCell', cItem.isEdit ? 'active' : '']"
                  :style="computedTdStyle(cItem.style)"
                  :rowspan="cItem.merge && cItem.merge.length == 2 ? cItem.merge[0] : 1"
                  :colspan="cItem.merge && cItem.merge.length == 2 ? cItem.merge[1] : 1"
                  @click="handleCellClick(cItem)"
                >
                  <template v-if="cItem.type == 'text' && !cItem.isEdit">
                    <pre>{{ cItem.value }}</pre>
                  </template>
                  <component
                    v-else
                    :ref="cItem.x + '-' + cItem.y + '-comp'"
                    :is="formatterCompType(cItem.type)"
                    :tdStyle="computedComponentStyle(cItem.style)"
                    :x="cItem.x"
                    :y="cItem.y"
                    :value="cItem.value"
                    :disabled="!operateBtn"
                    :dicData="cItem.dicData"
                    @input="handleCompInput"
                    @change="handleCompChange"
                    @handleAddRow="handleAddRow"
                    @handleDeleteRow="handleDeleteRow"
                    @handleClearFile="handleClearFile"
                    @uploadAttach="handleUpload"
                  />
                </td>
              </tr>
            </table>

            <!-- 检验报告 -->
            <table v-else ref="tableDom" id="pdf" class="template-table" border="1" cellspacing="0" cellpadding="0" :style="computedTableStyle">
              <colgroup>
                <col :style="{ width: (item.width || baseTableConfig.cellWidth) + 'px' }" v-for="(item, index) in xAxisNum" :key="index" />
              </colgroup>
              <tr v-for="(item, index) in dataJson.rows" :key="index">
                <td
                  v-for="(cItem, cIndex) in computedNotHide(item.cells)"
                  :key="cIndex"
                  :x="cItem.x"
                  :y="cItem.y"
                  :class="['tdCell', cItem.isEdit ? 'active' : '']"
                  :style="computedTdStyle(cItem.style)"
                  :rowspan="cItem.merge && cItem.merge.length == 2 ? cItem.merge[0] : 1"
                  :colspan="cItem.merge && cItem.merge.length == 2 ? cItem.merge[1] : 1"
                >
                  <pre>{{ cItem.value }}</pre>
                </td>
              </tr>
            </table>

            <div v-if="!operateBtn" title="打印线" class="print-line" :style="computedPrintLineStyle"></div>
          </div>
        </div>
        <div class="operateBtn" v-if="operateBtn">
          <el-button
            v-if="fieldsMap && fieldsMap['#{GET_DOCUMENT_API.idList}'] && fieldsMap['#{GET_DOCUMENT_API.idList}'].length < 2"
            size="small"
            type="primary"
            icon="el-icon-document"
            @click="handleSubmit('1')"
          >
            保存草稿
          </el-button>
          <el-button size="small" type="primary" v-preventReClick icon="el-icon-circle-plus-outline" @click="handleSubmit('2')">执行检验</el-button>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { propertyList } from './property.js';
import { letters } from './data.js';
import request from '@/router/axios';
import { isClickSameCell, getCellIndexByCoord, findParentWithClass, pageSizeInPixels } from './util.js';
import boxArea from './boxArea.vue';
import contextMenu from './contextMenu.vue';
import menuBtnGroups from './menuBtnGroups.vue';
import fieldList from './fieldList.vue';
import attrConfig from './attrConfig.vue';
import { mapGetters, mapState } from 'vuex';
import { submitResult } from '@/api/designer/apaasList';
import shdFormDesignText from './components/input.vue';
import shdFormDesignNumber from './components/inputNumber.vue';
import shdFormDesignRadio from './components/radio.vue';
import shdFormDesignCheckbox from './components/checkbox.vue';
import shdFormDesignSelect from './components/select.vue';
import shdFormDesignBtnAddRow from './components/btnAddRow.vue';
import shdFormDesignBtnDeleteRow from './components/btnDeleteRow.vue';
import shdFormDesignUploadAttachment from './components/uploadAttachment.vue';
import shdFormDesignDisplayAttachment from './components/displayAttachment.vue';
import { EventBus } from './event-bus.js';
export default {
  name: 'SHDFormDesigner',
  components: {
    boxArea,
    menuBtnGroups,
    contextMenu,
    fieldList,
    attrConfig,
    'shdFormDesign-text': shdFormDesignText,
    'shdFormDesign-number': shdFormDesignNumber,
    'shdFormDesign-radio': shdFormDesignRadio,
    'shdFormDesign-checkbox': shdFormDesignCheckbox,
    'shdFormDesign-select': shdFormDesignSelect,
    'shdFormDesign-btnAddRow': shdFormDesignBtnAddRow,
    'shdFormDesign-btnDeleteRow': shdFormDesignBtnDeleteRow,
    'shdFormDesign-uploadAttachment': shdFormDesignUploadAttachment,
    'shdFormDesign-displayAttachment': shdFormDesignDisplayAttachment
  },
  props: {
    operateBtn: {
      type: Boolean,
      default: true
    },
    liveParams: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      tablePreviewData: [],
      jsPDFOptions: {
        format: 'a4',
        pages: [
          { label: 'A0', value: 'a0' },
          { label: 'A1', value: 'a1' },
          { label: 'A2', value: 'a2' },
          { label: 'A3', value: 'a3' },
          { label: 'A4', value: 'a4' },
          { label: 'A5', value: 'a5' },
          { label: 'B0', value: 'b0' },
          { label: 'B1', value: 'b1' },
          { label: 'B2', value: 'b2' },
          { label: 'B3', value: 'b3' },
          { label: 'B4', value: 'b4' },
          { label: 'B5', value: 'b5' }
        ]
      },
      fieldsMap: {},
      template: {
        loading: false
      },
      startXGuide: 0,
      changeXAxisIndex: -1,
      xSublineGuideLeft: 0,
      showXSubline: false,
      showXSublineGuide: false,
      tooltip: {
        color: '',
        bgcolor: '',
        fontSize: 12,
        'font-weight': ['bold', 'normal'],
        'font-style': ['italic', 'normal'],
        'text-decoration': ['underline', 'none']
      },
      rules: {
        rows: [{ required: true, message: '请输入行数', trigger: 'change' }],
        columns: [{ required: true, message: '请输入列数', trigger: 'change' }]
      },
      contextMenu: {
        top: 0,
        left: 0
      },
      startX: '',
      startY: '',
      moveX: '',
      moveY: '',
      oldMoveX: '',
      oldMoveY: '',
      boxStyle: {
        width: 0,
        height: 0,
        top: 0,
        left: 0
      },
      showBoxArea: false,
      showContextMenu: false,
      propertyList: propertyList,
      copyDataStartX: -1,
      copyDataStartY: -1,
      timer: null
    };
  },
  computed: {
    ...mapState({
      cellInfo: (state) => state.form.cellInfo,
      dataJson: (state) => state.form.dataJson,
      apiJson: (state) => state.form.apiJson,
      submitJson: (state) => state.form.submitJson,
      dictJson: (state) => state.form.dictJson,
      histroyData: (state) => state.form.histroyData,
      histroyIndex: (state) => state.form.histroyIndex,
      baseTableConfig: (state) => state.form.baseTableConfig,
      boxAreaXY: (state) => state.form.boxAreaXY,
      xAxisNum: (state) => state.form.xAxisNum,
      yAxisNum: (state) => state.form.yAxisNum
    }),
    canvasStyle() {
      // +1修复表格边框线重叠问题导致X轴换行
      let xLen =
        this.xAxisNum.reduce((pre, cur) => {
          return pre + cur.width;
        }, 0) + 1;
      let yLen = this.yAxisNum.reduce((pre, cur) => {
        return pre + cur.height;
      }, 0);
      return {
        width: xLen + 'px',
        height: yLen + 'px'
      };
    },
    computedTableStyle() {
      if (this.dataJson.tableTotalWidth) {
        return {
          width: this.operateBtn ? this.dataJson.tableTotalWidth + 'px' : this.dataJson.tableTotalWidth * 0.75 + 'pt'
        };
      }
    },
    computedPrintLineStyle() {
      let pageStyle = pageSizeInPixels(this.jsPDFOptions.format);
      console.log('纸的像素尺寸：宽 ' + pageStyle.width + 'px, 高 ' + pageStyle.height + 'px');
      return {
        width: pageStyle.width + 'px',
        height: pageStyle.height + 'px'
      };
    },
    printStyle() {
      return {
        width: parseInt(this.computedPrintLineStyle.width),
        height: parseInt(this.computedPrintLineStyle.height)
      };
    },
    computedTdStyle(style) {
      return (style) => {
        return {
          ...style,
          'font-size': (style['font-size'] || 12) + 'px',
          height: (style.height || this.baseTableConfig.cellHeight) - 1 + 'px'
          // 'line-height': (style.height || this.baseTableConfig.cellHeight) - 1 + 'px'
        };
      };
    },
    computedComponentStyle(style) {
      return (style) => {
        return {
          width: (style.width || this.baseTableConfig.cellWidth) - 1 + 'px',
          'font-size': (style['font-size'] || 12) + 'px',
          height: (style.height || this.baseTableConfig.cellHeight) - 1 + 'px',
          'line-height': (style.height || this.baseTableConfig.cellHeight) - 1 + 'px'
        };
      };
    },
    formatterCompType(type) {
      return (type) => {
        return 'shdFormDesign-' + (type || 'text');
      };
    },
    formatterValue(item) {
      return (item) => {
        if (item.isForamtter && item.dataType != '3') {
          let fn = new Function('return ' + item.dataFormatter)();
          let newValue = fn(item.value);
          item.value = structuredClone(newValue);
          return item.value;
        } else {
          return item.value;
        }
      };
    },
    isNotSameCell() {
      return isClickSameCell(this.boxAreaXY.startX, this.boxAreaXY.startY, this.boxAreaXY.endX, this.boxAreaXY.endY);
    }
  },
  beforeDestroy() {
    clearInterval(this.timer);
    this.timer = null;
    this.$store.commit('form/clearDesignerData');
    window.removeEventListener('keydown', this.keyboardEvent, false);
    this.$refs.tableDom.removeEventListener('paste', this.handleParsePasteData, false);
    this.dataJson.rows = [];
  },
  methods: {
    setDataJson(dataJson) {
      dataJson.rows.forEach((row) => {
        row.cells.forEach((cell) => {
          if (cell.type == 'select') {
            let find = cell.dicData.find((item) => item.value == cell.value);
            cell.value = find ? find.label : '';
            cell.type = 'text';
          } else if (cell.type == 'radio') {
            let find = cell.dicData.find((item) => item.value == cell.value);
            cell.value = find ? find.label : '';
            cell.type = 'text';
          } else if (cell.type == 'number') {
            cell.value = cell.value;
            cell.type = 'text';
          } else if (['btnAddRow', 'btnDeleteRow', 'uploadAttachment', 'displayAttachment'].includes(cell.type)) {
            cell.value = '';
            cell.type = 'text';
          }
        });
      });
      this.$store.dispatch('form/setDataJson', dataJson);
    },
    async viewApaasTemplate(id, isCallApi = true) {
      const that = this;
      that.template.loading = true;
      that.fieldsMap = {};
      let data = await that.$store.dispatch('form/getFormTemplate', {
        id
      });
      let apiJson = JSON.parse(data.apiJson || '[]');
      // 串行处理api
      if (apiJson && apiJson.length > 0) {
        await that.handleApi(apiJson);
      }
      // 读取保存草稿数据
      if (that.fieldsMap['#{GET_DOCUMENT_API.apaasExamineContent}']) {
        let dataJson = JSON.parse(that.fieldsMap['#{GET_DOCUMENT_API.apaasExamineContent}'] || '{}');
        await this.$store.dispatch('form/setDataJson', dataJson);
        await this.$store.dispatch('form/setSubmitJson', dataJson.submitJson);
      }
      // 检测是否存在配置了api的单元格
      let apiCells = await that.getApiCells(data.content);
      if (apiCells && apiCells.length > 0) {
        // 处理单元格api请求;
        await that.handleCellApi(apiCells);
      } else {
        that.template.loading = false;
      }
      // EventBus事件
      that.handleEventBus();
      that.bindEvent();
      if (that.fieldsMap && that.fieldsMap['#{GET_DOCUMENT_API.idList}'] && that.fieldsMap['#{GET_DOCUMENT_API.idList}'].length < 2) {
        that.startTimeSave();
      }

      console.log(that.dataJson.rows, 'viewApaasTemplate');
    },
    startTimeSave() {
      const that = this;
      // 每隔30s定时保存一下草稿
      that.timer = setInterval(() => {
        that.handleSubmit('1', true);
      }, 30 * 1000);
    },
    bindEvent() {
      window.addEventListener('keydown', this.keyboardEvent, false);
      this.bindPasteEvent();
    },
    // ctrl快捷键操作
    keyboardEvent(e) {
      const that = this;
      const keyCodes = {
        37: 'left',
        38: 'top',
        39: 'right',
        40: 'bottom'
      };
      const { ctrlKey, keyCode } = e;
      console.log(keyCode, 'keyCode');
      let keyString = [];
      if (ctrlKey) keyString.push('ctrl');
      keyString.push(keyCodes[keyCode]);
      keyString = keyString.join('+');
      switch (keyString) {
        case 'left':
          that.handleMouseLeft();
          break;
        case 'top':
          that.handleMouseTop();
          break;
        case 'right':
          that.handleMouseRight();
          break;
        case 'bottom':
          that.handleMouseBottom();
          break;
        default:
          break;
      }
    },
    handleEventBus() {
      const that = this;
      if (that.dataJson.rows && that.dataJson.rows.length > 0) {
        that.dataJson.rows.forEach((item) => {
          item.cells.forEach((cItem) => {
            if (cItem.eventConfig && cItem.eventConfig.start) {
              let eventName = letters[cItem.x] + (Number(cItem.y) + 1) + '->' + cItem.eventConfig.targetCell;
              EventBus.off(eventName);
              EventBus.on(eventName, (result) => {
                let data = JSON.parse(result);
                console.log(data, 'EventBus:data');
                let cellData = structuredClone(that.dataJson.rows[data.y].cells[data.x]);
                console.log(cellData, 'cellData');
                if (cellData.type == 'displayAttachment') {
                  let result = that.dataJson.rows[data.y].cells[data.x].value || [];
                  let find = result.find((item) => item.originalName == data.value[0].originalName);
                  if (!find) {
                    result.push(data.value[0]);
                  }
                  that.dataJson.rows[data.y].cells[data.x].value = result;
                }
                // 数据类型：api接口
                if (cellData.dataType == '3') {
                  let cellQuery = new Function('return ' + JSON.stringify(cellData.query))();
                  // 将配置了api数据源的单元格请求参数重新赋值
                  let newCellQuery = that.handleCellQuery(cellQuery);
                  cellData.query = newCellQuery;
                  that
                    .queryData(cellData)
                    .then((result) => {
                      that.handleResult(result);
                    })
                    .catch((err) => {});
                }
              });
            }
          });
        });
      }
    },
    bindPasteEvent() {
      if (this.$refs.tableDom) {
        this.$refs.tableDom.addEventListener('paste', this.handleParsePasteData, false);
      }
    },
    handleParsePasteData(e) {
      const that = this;
      // 获取粘贴板数据
      let target = e.target;
      let parentTarget = findParentWithClass(target, 'template-table');
      if (!parentTarget) {
        return;
      }
      Array.from(e.clipboardData.items).forEach((item, index) => {
        const type = e.clipboardData.types[index];
        if (item.kind === 'string') {
          if (type === 'text/html') {
            that.handleHtmlPaste(item);
          }
        }
      });
    },
    // 处理HTML粘贴（Excel复制粘贴）
    handleHtmlPaste(item) {
      const that = this;
      item.getAsString((htmlStr) => {
        const dom = new DOMParser().parseFromString(htmlStr, 'text/html');
        const copyData = that.handleFormatterCopyData(dom);
        // 多单元格数据粘贴
        let isMultiple = copyData.filter((item) => item.cells.length > 0).length > 1;
        if (isMultiple) {
          const x = that.copyDataStartX;
          const y = that.copyDataStartY;
          copyData.forEach((row, rowIndex) => {
            const rowData = that.dataJson.rows[y - 1 + rowIndex];
            if (!rowData) return;
            row.cells.forEach((cell, cellIndex) => {
              if (x - 1 + cellIndex >= rowData.cells.length) return;
              const targetCell = rowData.cells[x - 1 + cellIndex];
              if (cell.value && targetCell) {
                targetCell.code = cell.value;
                targetCell.value = cell.value;
                if (rowIndex === 0 && cellIndex === 0) {
                  that.cellInfo.code = cell.value;
                  that.cellInfo.value = cell.value;
                }
              }
            });
          });
        }
      });
    },
    handleFormatterCopyData(dom) {
      let copyData = [];
      const tableDom = dom.querySelector('table');
      if (!tableDom) return [];
      tableDom.querySelectorAll('tr').forEach((item, rowIndex) => {
        let tdDoms = item.querySelectorAll('td');
        copyData.push({
          cells: []
        });
        if (tdDoms) {
          tdDoms.forEach((tdItem) => {
            let tdText = tdItem.innerText.replace(/\n/g, '').trim();
            copyData[rowIndex].cells.push({
              value: tdText
            });
          });
        }
      });
      return copyData;
    },
    handleCellQuery(data) {
      const that = this;
      let reg = /#{|}/g;
      if (typeof data != 'object' || data === null) {
        return data;
      }
      let newData = {};
      const dataKeys = Object.keys(data);
      dataKeys.forEach((key) => {
        const currentDataValue = data[key];
        if (currentDataValue === null || (typeof currentDataValue == 'string' && !currentDataValue.startsWith('#{'))) {
          newData[key] = currentDataValue;
        } else if (typeof currentDataValue == 'string' && currentDataValue.startsWith('#{')) {
          // 动态参数 #{}
          let coord = currentDataValue.replace(reg, '');
          let { x, y } = getCellIndexByCoord(coord); //通过坐标查询对应索引
          let tableCell = this.dataJson.rows[y].cells[x];
          newData[key] = tableCell.value;
        } else if (Array.isArray(currentDataValue)) {
          // 数组
          newData[key] = currentDataValue.map((item) => {
            return that.handleCellQuery(item);
          });
        } else {
          // 普通对象 递归赋值
          newData[key] = that.handleCellQuery(currentDataValue);
        }
      });
      return newData;
    },
    isSelectType(type) {
      return ['radio', 'checkbox', 'select'].includes(type);
    },
    handleResult(data) {
      const that = this;
      let cellData = that.dataJson.rows[data.y].cells[data.x];
      if (data.isForamtter) {
        let fn = new Function('return ' + data.dataFormatter)();
        let newValue = fn(data.params);
        if (this.isSelectType(data.type)) {
          cellData.dicData = newValue;
          if (!cellData.value && data.params && data.params.length > 0 && data.params[0].defaultValue) {
            cellData.value = data.params[0].defaultValue;
          }
        } else {
          cellData.value = newValue;
        }
      } else {
        if (this.isSelectType(data.type)) {
          cellData.dicData = data.params;
          if (!cellData.value && data.params && data.params.length > 0 && data.params[0].defaultValue) {
            cellData.value = data.params[0].defaultValue;
          }
        } else {
          cellData.value = data.params;
        }
      }
    },
    ajax(item, prePromise) {
      const that = this;
      return new Promise((resolve, reject) => {
        let route = Object.assign({}, that.liveParams);
        let query = {
          apiCode: item.showQuery.apiCode,
          parameterDatas: item.paramsForm
        };
        if (item.paramsForm && item.paramsForm.length > 0) {
          item.paramsForm.forEach((pItem) => {
            let reg = /#{|}/g;
            let pItemValue = pItem.value.replace(reg, '');
            let [apiCode, param] = pItemValue.split('.');
            prePromise.map((rItem) => {
              if (rItem.key == apiCode) {
                pItem.value = rItem.params[param];
              }
            });
          });
          query.parameterDatas = structuredClone(item.paramsForm);
          queryData(item.url, query);
        } else {
          // 没有依赖参
          for (const key in route) {
            let existingParam = query.parameterDatas.find((p) => p.code === key);
            if (existingParam && query.parameterDatas.length > 0) {
              query.parameterDatas.map((p) => {
                if (p.code == key) {
                  p.value = route[key];
                }
              });
            } else {
              query.parameterDatas.push({
                code: key,
                value: route[key]
              });
            }
          }
          queryData(item.url, query);
        }

        function queryData(url, query, method = 'POST') {
          console.log('query', query);
          request({
            url,
            method,
            data: query
          })
            .then((result) => {
              let data = result.data.data;
              if (Array.isArray(data)) {
                resolve({
                  key: item.code,
                  params: data[0]
                });
              } else {
                resolve({
                  key: item.code,
                  params: data
                });
              }
            })
            .catch((err) => {
              reject(err);
            });
        }
      });
    },
    // 串行处理api
    async handleApi(data) {
      const that = this;
      try {
        let resultList = await data.reduce(async (promiseChain, cur) => {
          const previousResults = await promiseChain;
          const currentResult = await that.ajax(cur, previousResults);
          return [...previousResults, currentResult];
        }, Promise.resolve([]));
        for (const item of resultList) {
          let code = item.key;
          if (item.params && Object.keys(item.params).length > 0) {
            for (const key in item.params) {
              that.fieldsMap[`#{${code}.${key}}`] = item.params[key];
            }
          } else {
            that.fieldsMap = {};
          }
        }
        console.log(that.fieldsMap, 'that.fieldsMap');
        that.dataJson.rows.forEach((item) => {
          item.cells.forEach((cItem) => {
            if (cItem.code) {
              if (typeof cItem.code == 'string') {
                cItem.code = cItem.code.trim();
              }
              if (that.fieldsMap[cItem.code] || typeof that.fieldsMap[cItem.code] == 'boolean') {
                if (cItem.isForamtter) {
                  let fn = new Function('return ' + cItem.dataFormatter)();
                  let newValue = fn(that.fieldsMap[cItem.code]);
                  cItem.value = newValue;
                } else {
                  cItem.value = that.fieldsMap[cItem.code];
                }
              }
            }
          });
        });
      } catch (error) {
        console.log(error);
      } finally {
      }
    },
    queryData(obj) {
      let { url, query, method = 'POST' } = obj;
      return new Promise((resolve, reject) => {
        request({
          url,
          method,
          data: query,
          headers: {
            'Content-Type': 'application/json'
          }
        })
          .then((result) => {
            resolve({
              x: obj.x,
              y: obj.y,
              isForamtter: obj.isForamtter,
              dataFormatter: obj.dataFormatter,
              params: result.data.data,
              type: obj.type
            });
          })
          .catch((err) => {
            reject(err);
          });
      });
    },
    // 找到所有配置了api的单元格
    getApiCells(data) {
      let content = JSON.parse(data || '{}').rows;
      // 找到所有配置了api的单元格
      let apiCells = [];
      if (content && content.length > 0) {
        for (let i = 0; i < content.length; i++) {
          for (let j = 0; j < content[i].cells.length; j++) {
            let cell = content[i].cells[j];
            if (cell.dataType == '3') {
              if (cell.query) {
                let isDynamic = this.checkIsDynamicParams(cell.query);
                if (!isDynamic) {
                  apiCells.push(cell);
                }
              }
            }
          }
        }
      }

      return apiCells;
    },
    // 检测是否为动态参数 如参数中包含#{A4}
    checkIsDynamicParams(query) {
      const that = this;
      if (Object.keys(query).length > 0) {
        for (const key in query) {
          let currentValue = query[key];
          if (typeof currentValue == 'string') {
            if (currentValue.startsWith('#{')) {
              return true;
            }
          }
          if (Array.isArray(currentValue)) {
            let isDynamic = currentValue.some((item) => {
              return that.checkIsDynamicParams(item);
            });
            if (isDynamic) {
              return true;
            }
          }
        }
      }
    },
    async handleCellApi(apiCells) {
      const that = this;
      Promise.all(apiCells.map((cell) => that.queryData(cell)))
        .then((result) => {
          console.log(result, 'handleCellApi');
          result.map((item) => {
            that.handleResult(item);
          });
        })
        .finally(() => {
          that.template.loading = false;
        });
    },
    computedNotHide(cell) {
      return cell.filter((item) => !item.hide);
    },
    // y:y轴索引  x：x轴索引 merge:[rowspan,colspan]
    handleCellClick(item) {
      if (item.isLock) {
        this.$message.warning('当前单元格已锁定,若想修改请先解锁！');
        return false;
      }

      this.dataJson.rows.map((rItem) => {
        rItem.cells.map((rcItem) => {
          rcItem.isEdit = false;
        });
      });
      if (item.type != 'text') return false;
      console.log(item, 'cItem点击事件');
      this.copyDataStartX = item.x + 1;
      this.copyDataStartY = item.y + 1;
      if (item.type == 'text') {
        this.$set(item, 'isEdit', true);
        this.$nextTick(() => {
          let comp = this.$refs[item.x + '-' + item.y + '-comp'];
          if (comp && comp[0]) {
            comp[0].handleFocus(item.x, item.y);
          }
        });
      }
      let cellData = this.dataJson.rows[item.y].cells[item.x];
      let cellInfoStyle = cellData.style || {};
      // 设置选中单元格的详细信息
      this.$store.commit('form/setCellInfo', {
        ...cellData,
        x: item.x + 1,
        y: item.y + 1,
        xName: this.xAxisNum[item.x].label,
        style: cellInfoStyle,
        isEdit: cellData.isEdit || false,
        apiField: cellData.apiField || false,
        isForamtter: cellData.isForamtter || false,
        dataType: cellData.dataType || '1',
        eventConfig: cellData.eventConfig || {}
      });
    },
    handleCompInput(config) {
      let { value, x, y } = config;
      console.log(config, 'handleCompInput');
      this.$set(this.cellInfo, 'value', value);
      this.$set(this.dataJson.rows[y].cells[x], 'value', value);
    },
    handleCompChange(config) {
      let { value, x, y } = config;
      console.log('handleCompChange', value);
      this.$set(this.cellInfo, 'value', value);
      this.$set(this.dataJson.rows[y].cells[x], 'value', value);
      let tdCell = this.dataJson.rows[y].cells[x];
      if (tdCell.eventConfig && tdCell.eventConfig.start) {
        // 触发事件
        let eventName = letters[x] + (Number(y) + 1) + '->' + tdCell.eventConfig.targetCell;
        let targetCellX = tdCell.eventConfig.targetCell.replace(/\d/g, '');
        targetCellX = letters.findIndex((item) => item == targetCellX);
        let targetCellY = tdCell.eventConfig.targetCell.match(/\d+/g)[0] - 1;
        EventBus.emit(
          eventName,
          JSON.stringify({
            value: value,
            x: targetCellX,
            y: targetCellY
          })
        );
      }
    },
    handleUpload(config) {
      let { data, x, y } = config;
      let tdCell = this.dataJson.rows[y].cells[x];
      if (tdCell.eventConfig && tdCell.eventConfig.start) {
        // 触发事件
        let eventName = letters[x] + (Number(y) + 1) + '->' + tdCell.eventConfig.targetCell;
        let targetCellX = tdCell.eventConfig.targetCell.replace(/\d/g, '');
        targetCellX = letters.findIndex((item) => item == targetCellX);
        let targetCellY = tdCell.eventConfig.targetCell.match(/\d+/g)[0] - 1;
        EventBus.emit(
          eventName,
          JSON.stringify({
            value: data,
            x: targetCellX,
            y: targetCellY
          })
        );
      }
    },
    handleSubmitData(index, number) {
      const that = this;
      let reg = /#{|}/g;
      let qmsDocumentDTO = that.submitJson['qmsDocumentDTO'];
      for (const key in qmsDocumentDTO) {
        let currentValue = qmsDocumentDTO[key];
        if (typeof currentValue == 'string' && currentValue.startsWith('#{')) {
          let currentValueStr = currentValue.replace(reg, '');
          let splitLen = currentValueStr.split('.').length;
          if (splitLen == 1) {
            let letter = currentValueStr.replace(/\d/g, '');
            let num = Number(currentValueStr.match(/\d+/)[0]);
            if (num > index) {
              qmsDocumentDTO[key] = `#{${letter}${num + number}}`;
            }
          }
        }
      }
    },
    handleAddRow(config) {
      const that = this;
      let { btnAddRowField } = config;
      let addRowArray = that.submitJson[btnAddRowField];
      let currentRowIndex;
      console.log(that.submitJson, 'submitJson');
      console.log(btnAddRowField, 'btnAddRowField');
      if (addRowArray && addRowArray.length > 0) {
        for (const item of addRowArray) {
          for (const key in item) {
            let currentValue = item[key];
            let startStr = currentValue.split('-')[0];
            let endLetter = currentValue.split('-')[1].split('}')[0].replace(/\d/g, '');
            let endNum = Number(currentValue.split('-')[1].match(/\d+/g)[0]) + 1;
            item[key] = `${startStr}-${endLetter}${endNum}}`;
            currentRowIndex = endNum;
          }
        }
      }
      that.handleSubmitData(currentRowIndex, 1);
      console.log(that.submitJson, 'that.submitJson');
      that.$store.commit('form/renderSubmitJson', that.submitJson);
      that.$store.commit('form/addRows', {
        index: currentRowIndex - 2,
        level: 'comp'
      });
      // 打通事件处理
      that.handleEventBus();
    },
    handleDeleteRow(config) {
      const that = this;
      let { btnAddRowField, x, y } = config;
      let addRowArray = that.submitJson[btnAddRowField];
      if (addRowArray && addRowArray.length > 0) {
        for (const item of addRowArray) {
          for (const key in item) {
            let currentValue = item[key];
            let startStr = currentValue.split('-')[0];
            let startNum = Number(startStr.match(/\d+/g)[0]);
            let endLetter = currentValue.split('-')[1].split('}')[0].replace(/\d/g, '');
            let endNum = Number(currentValue.split('-')[1].match(/\d+/g)[0]) - 1;
            if (endNum < startNum) {
              // item[key] = '';
              return false;
            } else {
              item[key] = `${startStr}-${endLetter}${endNum}}`;
            }
          }
        }
      }

      that.handleSubmitData(y, -1);
      console.log(that.submitJson, 'that.submitJson');
      that.$store.commit('form/renderSubmitJson', that.submitJson);
      that.$store.commit('form/deleteRows', {
        index: y, // 删除的数据行索引
        count: 1 // 删除的数据行数
      });
    },
    handleClearFile(config) {
      const that = this;
      let { x, y, data } = config;
      that.$set(that.dataJson.rows[y].cells[x], 'value', data);
    },
    /**
     * @description: 提交数据
     * @param {*} status: 1:保存草稿 2:执行检验
     * @param {*} autoSave:自动保存
     */
    handleSubmit(status, autoSave = false) {
      const that = this;
      function formatterSubmitJson(data) {
        let reg = /#{|}/g;
        if (typeof data != 'object' || data === null) {
          return data;
        }
        let newData = {};
        const dataKeys = Object.keys(data);
        dataKeys.forEach((key) => {
          const currentDataValue = data[key];
          // null 和 字符串不是动态参数 的值 直接赋值
          if (currentDataValue === null || (typeof currentDataValue == 'string' && !currentDataValue.startsWith('#{'))) {
            newData[key] = currentDataValue;
          } else if (typeof currentDataValue == 'string' && currentDataValue.startsWith('#{')) {
            // 动态参数 #{}
            let submitJsonValue = currentDataValue.replace(reg, '');
            let splitLen = submitJsonValue.split('.').length;
            if (splitLen > 1) {
              // 直接将所有接口返回值赋值给动态参数
              newData[key] = that.fieldsMap[currentDataValue];
            } else {
              let xIndex = letters.findIndex((item) => item == submitJsonValue.replace(/\d/g, ''));
              let yIndex = submitJsonValue.match(/\d+/)[0] - 1;
              newData[key] = that.dataJson.rows[yIndex].cells[xIndex].value;
            }
          } else if (Array.isArray(currentDataValue)) {
            // 数组类型
            let startNum = 0;
            let endNum = 0;
            currentDataValue.map((item) => {
              Object.values(item).map((iItem) => {
                if (typeof iItem == 'string' && iItem.startsWith('#{')) {
                  let iItemNum = iItem.replace(reg, '');
                  let numArrs = iItemNum.match(/\d+/g);
                  startNum = Number(numArrs[0]);
                  endNum = Number(numArrs[1]);
                }
              });
            });
            let newArr = [];
            for (let i = startNum; i <= endNum; i++) {
              let obj = {};
              for (const key in currentDataValue[0]) {
                let item = currentDataValue[0][key];
                let iItemNum = item.replace(reg, '');
                let letter = iItemNum.replace(/\d/g, '')[0];
                let columnIndex = letters.findIndex((item) => item == letter);
                if (that.dataJson.rows[i - 1] && that.dataJson.rows[i - 1].cells) {
                  obj[key] = that.dataJson.rows[i - 1].cells[columnIndex].value;
                }
              }
              newArr.push(obj);
            }
            newData[key] = newArr;
          } else {
            // 普通对象 递归赋值
            newData[key] = formatterSubmitJson(currentDataValue);
          }
        });

        return newData;
      }

      let result = formatterSubmitJson(that.submitJson);
      let content = structuredClone(that.dataJson);
      content.rows.forEach((item) => {
        item.cells.forEach((cItem) => {
          // 执行检验删除isEdit和isLock
          if (status == 2) {
            delete cItem.isEdit;
            delete cItem.isLock;
          }
        });
      });
      if (status == 1) {
        content.submitJson = that.submitJson;
      }
      result.apaasExamineContent = JSON.stringify(content);
      if (result.qmsDocumentDTO) {
        result.qmsDocumentDTO.status = status;
      }
      console.log(content, '提交参数content');
      let documentType = 'iqc';
      if (that.liveParams && that.liveParams.documentType) {
        documentType = that.liveParams.documentType.toLowerCase();
      }
      submitResult(result, documentType)
        .then(() => {
          if (!autoSave) {
            that.$message.success('保存成功');
            that.$emit('closeDialog');
          }
        })
        .catch(() => {});
    },
    cancel() {
      that.$emit('closeDialog');
    },
    handleMouseLeft() {
      const that = this;
      let { x, y } = that.cellInfo;
      if (x <= 1) return;
      const leftCell = that.dataJson.rows[y - 1].cells[x - 1 - 1];
      console.log(leftCell, 'leftCell');
      if (!leftCell.hide) {
        that.handleCellClick(leftCell);
      } else {
        let mergeCell = leftCell.mergeCell;
        if (mergeCell) {
          let x = mergeCell.split('-')[0];
          let y = mergeCell.split('-')[1];
          that.handleCellClick(that.dataJson.rows[y].cells[x]);
        }
      }
    },
    handleMouseTop() {
      const that = this;
      let { x, y } = that.cellInfo;
      if (y <= 1) return;
      const topCell = that.dataJson.rows[y - 1 - 1].cells[x - 1];
      console.log(topCell, 'topCell');
      if (!topCell.hide) {
        that.handleCellClick(topCell);
      } else {
        let mergeCell = topCell.mergeCell;
        if (mergeCell) {
          let x = mergeCell.split('-')[0];
          let y = mergeCell.split('-')[1];
          that.handleCellClick(that.dataJson.rows[y].cells[x]);
        }
      }
    },
    handleMouseRight() {
      const that = this;
      let { x, y, merge } = that.cellInfo;
      if (x >= that.dataJson.rows[y - 1].cells.length) return;
      const rightCell = that.dataJson.rows[y - 1].cells[x - 1 + merge[1]];
      console.log(rightCell, 'rightCell');
      if (!rightCell.hide) {
        that.handleCellClick(rightCell);
      } else {
        if (rightCell.mergeCell) {
          let mergeCell = rightCell.mergeCell;
          if (mergeCell) {
            let x = mergeCell.split('-')[0];
            let y = mergeCell.split('-')[1];
            that.handleCellClick(that.dataJson.rows[y].cells[x]);
          }
        }
      }
    },
    handleMouseBottom() {
      const that = this;
      let { x, y, merge } = that.cellInfo;
      if (y >= that.dataJson.rows.length) return;
      const bottomCell = that.dataJson.rows[y - 1 + merge[0]].cells[x - 1];
      console.log(bottomCell, 'bottomCell');
      if (!bottomCell.hide) {
        that.handleCellClick(bottomCell);
      } else {
        if (bottomCell.mergeCell) {
          let mergeCell = bottomCell.mergeCell;
          if (mergeCell) {
            let x = mergeCell.split('-')[0];
            let y = mergeCell.split('-')[1];
            that.handleCellClick(that.dataJson.rows[y].cells[x]);
          }
        }
      }
    },
    exportPdf() {
      const that = this;
      const ele = document.getElementById('pdf');
      let pageStyle = pageSizeInPixels(this.jsPDFOptions.format);
      var opt = {
        margin: 10,
        filename: that.dataJson.name + '.pdf',
        html2canvas: { scale: 2 },
        jsPDF: {
          compress: true,
          unit: 'pt',
          format: this.jsPDFOptions.format, //长和宽
          // format: [pageStyle.height, pageStyle.width],
          // landscape:横向 portrait：纵向
          orientation: 'portrait'
        }
      };
      const html2pdf = this.$html2pdf;
      setTimeout(() => {
        html2pdf().set(opt).from(ele).save();
        this.$message.success('导出成功！');
      });
    },
    exportExcel() {
      const that = this;
      that.exportTableToExcel('pdf', that.dataJson.name);
    },
    exportTableToExcel(tableID, filename = 'export.xlsx') {
      var downloadLink;
      var dataType = 'application/vnd.ms-excel';
      var tableSelect = document.getElementById(tableID);
      var tableHTML = tableSelect.outerHTML.replace(/ /g, '%20');
      filename = filename ? filename + '.xlsx' : 'export.xlsx';
      downloadLink = document.createElement('a');
      document.body.appendChild(downloadLink);
      if (navigator.msSaveOrOpenBlob) {
        var blob = new Blob(['\ufeff', tableHTML], {
          type: dataType
        });
        navigator.msSaveOrOpenBlob(blob, filename);
      } else {
        downloadLink.href = 'data:' + dataType + ', ' + tableHTML;
        downloadLink.download = filename;
        downloadLink.click();
      }
    }
  }
};
</script>
<style scoped lang="scss">
.designer {
  .container {
    height: calc(100vh - 115px);
    background-color: #fff;

    .editorArea {
      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: column;
      .menuBtns {
        margin-bottom: 5px;
        .menuItem {
          margin-right: 10px;
        }
      }
      .editor-canvas {
        width: 100%;
        height: 100%;
        overflow: auto;
        flex: 1;
        .grid-canvas {
          width: 100%;
          height: 100%;
          position: relative;

          table {
            table-layout: fixed;
            border-collapse: collapse;
            word-break: break-all;
            word-wrap: break-word;
            border-width: 0;
            tr {
              td {
                background-color: #fff;
                user-select: none;
                text-align: center;
                position: relative;

                ::v-deep .el-input__inner {
                  background: #fff;
                }
                &.active {
                  background: linear-gradient(180deg, rgba(181, 209, 255, 0.34), rgba(181, 209, 255, 0.34));
                  ::v-deep .el-input__inner {
                    background: #ffeb3b;
                  }
                }
              }
            }
          }
          .print-line {
            background: #9e9e9e2b;
            position: absolute;
            top: 0;
            z-index: 10;
          }
        }
      }
      .operateBtn {
        margin-top: 10px;
        text-align: right;
        height: 40px;
      }
    }
  }
}
</style>
